/*
The MIT License (MIT)

Copyright (c) 2013 Mike Dapiran, Brian May, Richard Pospesel, and Bert Wierenga

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software 
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "ParticleSystem.h"
#include <D3D11.h>
#include "../Managers/DX11Manager.h"
#include "tinyxml.h"
#include "../Content/VertexShader.h"
#include "../Components/MeshRenderer.h"
#include "../Content/MeshFilter.h"
#include "../HLSLCPPDeclarations/Texture2DMappings.fx"
#include "../Content/VertexShader.h"
#include "../Content/PixelShader.h"
#include "../Content/GeometryShader.h"

#include <algorithm>

namespace Hogshead
{
	namespace DX11Rendering
	{
		ComponentCPP(ParticleSystem)

		//Default Constructor
		//	-acquire the render info object
		//	-register all variables with the parameter field
		//	-set default values where possible
		ParticleSystem::ParticleSystem(void) : _process_handle(-1)
		{

		
		
			////set the default number of particles
			_max_particles = 0;

			//register all variables with the parameter field
			_pf.registerVariable(ParameterField::String, "initialVelocitySpace", &_velocity_space);
			//_pf.registerVariable(ParameterField::String, "initialVelocitySpace", &_birth_space);
			_pf.registerVariable(ParameterField::String, "blending", &_blending);
			_pf.registerVariable(ParameterField::Int, "maxParticles", &_max_particles);
			_pf.registerVariable(ParameterField::Int, "numEmitters", &_num_emitters);
			_pf.registerVariable(ParameterField::Bool, "zorient", &_z_orient);
			_pf.registerVariable(ParameterField::Int, "cloneKey", &_clone_key);

			_pf.registerVariable(ParameterField::Int, "process_handle", &_process_handle);

			_pf.registerVariable(ParameterField::Bool, "neverCull", &_never_cull);
			_never_cull = true;

			_modifier_message = NULL;
			
			this->_pulse_time = 0;
			this->registerMessageCallback<SetParticleSystemEnabledMessage>(handle_enabled_message);
			this->registerMessageCallback<ParticleSystemPulseMessage>(handle_pulse_message);
			this->registerMessageCallback<SetParticleSystemAttributes>(handle_attributes_message);

			_clone_key = -1;

			_mesh_renderer = NULL;

			_max_particles = 0;
			_num_emitters = 0;
			_blending = "";
			_mesh_renderer_name = "";

			_init_run = true;

			_enabled = 0.0f;

			_rotation = Vector2::zero;

			_texture = NULL;
		
			_z_orient = true;

			_alerted = false;

			_mesh_id = -1;
		}

		ParticleSystem::~ParticleSystem(void)
		{

		}


		//Finalize Method
		//	-release the render info object back to the factory
		void ParticleSystem::finalize()
		{
			if(_modifier_message)
				Factory::release(_modifier_message);
		}

		//Clone Method
		//	-acquire a new particle system object
		//	-copy all variables over to the new object
		IComponent* ParticleSystem::clone() const
		{
			ParticleSystem* new_sys = Factory::acquire<ParticleSystem>();
			new_sys->_birth_space = this->_birth_space;
			new_sys->_blending = this->_blending;
			new_sys->_cam_forward = this->_cam_forward;
			new_sys->_cam_right = this->_cam_right;
			new_sys->_cam_up = this->_cam_up;
			new_sys->_max_particles = this->_max_particles;
			new_sys->_mesh_renderer_name = this->_mesh_renderer_name;
			new_sys->_num_emitters = this->_num_emitters;
			new_sys->_clone_key = this->_clone_key;
			new_sys->_never_cull = this->_never_cull;
			new_sys->_mesh_filter_key = this->_mesh_filter_key;
			new_sys->_mesh_id = this->_mesh_id;

			return new_sys;
		}

		//Update function
		//	-update the world rotation of the system
		//	-This is only used in the local particle system shaders
		//		NOTE: This functionality should be placed in a new component
		void ParticleSystem::update(const GameTimer& in_gt)
		{
			if(_pulse_time > 0)
			{
				this->_pulse_time -= in_gt.getUpdateDelta();
				if(this->_pulse_time < 0)
				{
					this->_enabled = 0;
					ConstantBufferModifier* cbm = Factory::acquire<ConstantBufferModifier>();
					cbm->_names.add("gEnabled");
					cbm->_data.add(&this->_enabled);
					cbm->_types.add(Primitive::HFLOAT);
					cbm->_register = 3;
					Messenger::sendMessage(cbm, this->_mesh_renderer);
				}
			}

			if(in_gt.isDrawCycle())
			{
				_rot_matrix = this->getParentGameObject()->getTransform().getWorldRotation();
				_game_time = in_gt.getGameTime();
				_time_step = in_gt.getDrawDelta();
				_cam_up = Vector4(_dx11_director->_active_camera->getUp(),1);
				_cam_right = Vector4(_dx11_director->_active_camera->getRight(),1);
				_cam_forward = Vector4(_dx11_director->_active_camera->getForward(),1);
				

				Messenger::forwardMessage(this->_modifier_message, this->_mesh_renderer);
				ParticleBufferInfo* pbi = (ParticleBufferInfo*)_mesh_renderer->_process_specific_data;
				if(pbi->_already_updated)
				{
					if(!this->_mesh_renderer->_registered)
					{
						//alert(StringBuilder() << "Mesh Renderer for particle system never got registered (probably not initialized)\n" 
							//<< *(this->getParentGameObject()));
					}
					if(!_alerted)
					{
						//alert(StringBuilder() << "Particle Systems may be broken: please examine game object\n" << *(this->getParentGameObject()));
						_alerted = true;
					}
				}

				pbi->_already_updated = true;

			}

			

			//this->_render_info->_particle_info._rotMat = this->getParentGameObject()->getTransform().getWorldRotation();
		}

		//Initialize Method
		//	-register this component with the DX11Director
		//	-create the random texture used in the shader
		//	-create the initial vertex buffer of the particle system
		void ParticleSystem::initialize()
		{
			_mesh_renderer = NULL;
			_modifier_message = Factory::acquire<ConstantBufferModifier>();

			this->_modifier_message->_register = 4;

			this->_modifier_message->_types.add(HMATRIX4);
			this->_modifier_message->_types.add(HFLOAT);
			this->_modifier_message->_types.add(HFLOAT);
			this->_modifier_message->_types.add(HVECTOR4);
			this->_modifier_message->_types.add(HVECTOR4);
			this->_modifier_message->_types.add(HVECTOR4);
	
			this->_modifier_message->_names.add("rotMatrix");
			this->_modifier_message->_names.add("gameTime");
			this->_modifier_message->_names.add("timeStep");
			this->_modifier_message->_names.add("camUp");
			this->_modifier_message->_names.add("camRight");
			this->_modifier_message->_names.add("camForward");

			this->_modifier_message->_data.add(&_rot_matrix);
			this->_modifier_message->_data.add(&_game_time);
			this->_modifier_message->_data.add(&_time_step);
			this->_modifier_message->_data.add(&_cam_up);
			this->_modifier_message->_data.add(&_cam_right);
			this->_modifier_message->_data.add(&_cam_forward);

			if(getParentScene())
			{
				if(this->getParentScene()->getDirector("DX11Director"))
				{
					_dx11_director = this->getParentScene()->getDirector("DX11Director")->as<DX11Director>();
					_dx11_director->registerComponent(this);
				}
				
			}
			
			_init_run = true;
			
			auto mesh_renderers = this->getParentGameObject()->getComponentsOfType<MeshRenderer>();
			for(int i = 0; i < mesh_renderers.length(); i++)
			{
				if(!mesh_renderers[i]->_taken && mesh_renderers[i]->_particle_system)
				{
					if(this->_mesh_renderer)
					{
						error(StringBuilder() << "We've already found our mesh renderer! What is this?!\n" << this->_mesh_renderer_name 
							<< *(this->getParentGameObject()));
					}

					this->_mesh_renderer = mesh_renderers[i];

					this->_mesh_renderer->_taken = true;
					
					this->_mesh_renderer->_never_cull = this->_never_cull;

					ParticleBufferInfo* pbi = (ParticleBufferInfo*)this->_mesh_renderer->_process_specific_data;
					pbi->_first_run = true;

					String mesh_filter_key = this->_mesh_filter_key;

					CulledBody* cb = this->getParentGameObject()->getComponentOfType<CulledBody>();
					if(!_never_cull && !cb)
						error(StringBuilder() << "Particle System requires a culling body: " << endl << this->getParentGameObject()->getName() <<
						endl << "Texture: " << pbi->getParticleTexture()->getPath());

					//make our random texture
					Vector4 random_values[1024];
//#ifdef _VERBOSE
					//hout <<"NEXT---------------------------------------------------------------------------" << endl;
//#endif
					for(int i = 0; i < 1024; i++)
					{
						random_values[i].x = (float)Math::random().nextDouble(-1.0,1.0);
						random_values[i].y = (float)Math::random().nextDouble(-1.0,1.0);
						random_values[i].z = (float)Math::random().nextDouble(-1.0,1.0);
						random_values[i].W = (float)Math::random().nextDouble(-1.0,1.0);
						//hout << random_values[i] << endl;
					}
//#ifdef _VERBOSE
			
//#endif

					D3D11_SUBRESOURCE_DATA init_data;
					init_data.pSysMem = random_values;

					//creat the texture
					D3D11_TEXTURE1D_DESC tex_desc;
					tex_desc.ArraySize = 1;
					tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
					tex_desc.CPUAccessFlags = 0;
					tex_desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
					tex_desc.Usage = D3D11_USAGE_IMMUTABLE;
					tex_desc.Width = 1024;
					tex_desc.MiscFlags = 0;
					tex_desc.MipLevels = 1;
			
					ID3D11Texture1D* random_texture;
					HRESULT hr =  DX11Manager::createTexture1D(&tex_desc, &init_data, &random_texture);
					if(hr != S_OK)
					{
						error("ERROR: Random Texture could not be created");
					}

					//create the texture resource view to our random texture
					D3D11_SHADER_RESOURCE_VIEW_DESC view_desc;
					view_desc.Format = tex_desc.Format;
					view_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
					view_desc.Texture1D.MipLevels = tex_desc.MipLevels;
					view_desc.Texture1D.MostDetailedMip = 0;
			
					ID3D11ShaderResourceView* rand_srv = NULL;
					if(DX11Manager::createShaderResourceView(random_texture, &view_desc, &rand_srv) != S_OK)
					{
						error("ERROR: Random Texture could not be created");
					}
			
					random_texture->Release();

					Texture* rand_texture = Factory::acquire<Texture>();
					rand_texture->explicitLoadFromData(rand_srv);
					//ContentLibrary::explicitLoadFromData<Texture>(StringBuilder() << (String)mesh_filter_key << "_random_texture",
						//StringBuilder() << (String)mesh_filter_key << "_random_texture", rand_srv);

					pbi->setRandomTexture(rand_texture);


					//create our initial buffer
					Vector<Particle> part;
					for(UINT i = 0; i < _num_emitters; i++)
					{
						part.add(Particle());
						part[i]._pos = Vector3(0,0,0);
						part[i]._velocity = Vector3(0,0,0);
						part[i]._accel = Vector3(0,0,0);
						part[i]._size = Vector2(0.0f,0.0f);
						part[i]._ID = i;
						part[i]._age = 0.0f;
						part[i]._type = 0;
						part[i]._lifetime = 0.0f;
						part[i]._rotation = 0.0f;
					}

					D3D11_BUFFER_DESC bd;
					ZeroMemory(&bd, sizeof(bd));
					bd.Usage = D3D11_USAGE_DEFAULT;
					bd.ByteWidth = sizeof(Particle) * _num_emitters;
					bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
					bd.CPUAccessFlags = 0;
					bd.MiscFlags = 0;
					bd.StructureByteStride = sizeof(Particle);

					_num_emitters = this->_num_emitters;

					//initial data contains only the emitters we use
					D3D11_SUBRESOURCE_DATA InitData;
					ZeroMemory(&InitData, sizeof(InitData));
					InitData.pSysMem = (const Particle*)part;

					ID3D11Buffer* init_buff = NULL;
					hr = DX11Manager::createBuffer(&bd, &InitData, &init_buff);
					pbi->setInitBuffer(init_buff);
			
					pbi->_particle_size = sizeof(Particle);
					pbi->_num_particles = _num_emitters;
					_mesh_renderer->_process_specific_data = pbi;
			
			
		#ifdef _DEBUG
					//name our initial buffer for DX debugging
					const char init_string[] = "init Buffer";
					hr = pbi->getInitBuffer()->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof(init_string)-1, init_string );
					if(hr != S_OK)
					{
						StringBuilder sb;
						sb << "ERROR ON LOAD: Init Buffer could not be named";
						DX11Manager::_logger->write(sb);
						error(sb);
					}

		#endif

					//create the vertex buffer for the stream output
					ZeroMemory(&bd, sizeof(bd));
					bd.Usage = D3D11_USAGE_DEFAULT;
					bd.ByteWidth = sizeof(Particle) * _max_particles;
					bd.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_STREAM_OUTPUT;
					bd.CPUAccessFlags = 0;
					bd.MiscFlags = 0;
					bd.StructureByteStride = sizeof(Particle);

					ID3D11Buffer* so_buff = NULL;
					hr = DX11Manager::createBuffer(&bd, NULL, &so_buff);
					pbi->setStreamOutBuffer(so_buff);


					if(hr != S_OK)
					{
						throw new Exception("stream out buffer could not be created");
					}

		#ifdef _DEBUG
					const char stream_out_string[] = "stream out Buffer";
					hr = pbi->getStreamOutBuffer()->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof(stream_out_string)-1, stream_out_string );
					if(hr != S_OK)
					{
						StringBuilder sb;
						sb << "ERROR ON LOAD: stream out Buffer could not be named";
						DX11Manager::_logger->write(sb);
						error(sb);
					}
		#endif
					//create the vertex buffer for drawing the particles
					ZeroMemory(&bd, sizeof(bd));
					bd.Usage = D3D11_USAGE_DEFAULT;
					bd.ByteWidth = sizeof(Particle) * _max_particles;
					bd.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_STREAM_OUTPUT;
					bd.CPUAccessFlags = 0;
					bd.MiscFlags = 0;
					bd.StructureByteStride = sizeof(Particle);

					ID3D11Buffer* draw_buff = NULL;
					hr = DX11Manager::createBuffer(&bd, NULL, &draw_buff);
					pbi->setDrawBuffer(draw_buff);

					if(hr != S_OK)
					{
						throw new Exception("draw buffer could not be created");
					}
		#ifdef _DEBUG
					const char draw_string[] = "draw Buffer";
					hr = pbi->getDrawBuffer()->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof(draw_string)-1, draw_string );
					if(hr != S_OK)
					{
						StringBuilder sb;
						sb << "ERROR ON LOAD: draw Buffer could not be named";
						DX11Manager::_logger->write(sb);
						error(sb);
					}
		#endif

					pbi->_particle_size = sizeof(Particle);
		
					return;
					
				}
			}


		}

		//message Method
		//	-this method allows the particle system to be updated by
		//	other components using our messaging system
		void ParticleSystem::message(const IMessage* in_message)
		{
			/*if(in_message->is<ParticleSystemState>())
			{
				this->_render_info->_particle_info._enabled = in_message->as<ParticleSystemState>()->_enabled;
			}*/
		}

	
		Vector4 ParticleSystem::getPosition()
		{
			return Vector4(this->getParentGameObject()->getTransform().getWorldPosition(), 1.0f);
		}

		//readXML Method
		//	-read in all the child nodes of the particle system in order to
		//	 get the texture, material and various shaders needed to render
		//	 the system
		IComponent* ParticleSystem::readXML(const String& in_xml)
		{
		
			//int test = sizeof(Particle);
			IComponent::readXML(in_xml);

			//set our texture to NULL in case we don't have one
			//this->_render_info->_particle_texture = NULL;

			//parse the String for what we need
			TiXmlDocument document;
			document.Parse(in_xml);

			TiXmlElement* root_element = document.RootElement();
			String root_tag(root_element->Value());

			TiXmlNode* child_node = NULL;
			TiXmlElement* child_element;
			while(child_node = root_element->IterateChildren(child_node))
			{
				child_element = child_node->ToElement();
				if(!child_element)
					continue;

				String tag(child_element->Value());
				if(tag.equals("ConstantBufferGroup"))
				{
					//hand the correct xml block to our ConstantBufferGroup
					//so that it can create itself.
					_particle_info.readXML( String(*child_element) );
				}
				else if(tag.equals("ContentXML"))
				{
					const char* type = child_element->Attribute("type");
					if(String(type).equals("Texture"))
					{
						_texture = ContentLibrary::loadAndParseContentXML(child_element->Attribute("path"))->as<Texture>();
					}
				}
			}


			_mesh_renderer = Factory::acquire<MeshRenderer>();
			//part_mesh_renderer->_generates_shadows = false;

			HashTable<int, Technique*> default_techniques;

			/*if(_birth_space.equals("local"))
			{
				if(_velocity_space.equals("local") && _z_orient && _alpha_blended)
				{
					default_techniques.add(Pair<Technique*, String>(ContentLibrary::getContent<Technique>("ParticleSystem_birthlocal_velocitylocal_zorient_alphablended"), _process));
				}
				else if(_velocity_space.equals("world") && _z_orient && _alpha_blended)
				{
					default_techniques.add(Pair<Technique*, String>(ContentLibrary::getContent<Technique>("ParticleSystem_birthlocal_velocityworld_zorient_alphablended"), _process));
				}
				else if(_velocity_space.equals("local") && !_z_orient && _alpha_blended)
				{
					default_techniques.add(Pair<Technique*, String>(ContentLibrary::getContent<Technique>("ParticleSystem_birthlocal_velocitylocal_alphablended"), _process));
				}
				else if(_velocity_space.equals("world") && !_z_orient && _alpha_blended)
				{
					default_techniques.add(Pair<Technique*, String>(ContentLibrary::getContent<Technique>("ParticleSystem_birthlocal_velocityworld_alphablended"), _process));
				}
				else if(_velocity_space.equals("local") && _z_orient && !_alpha_blended)
				{
					default_techniques.add(Pair<Technique*, String>(ContentLibrary::getContent<Technique>("ParticleSystem_birthlocal_velocitylocal_zorient"), _process));
				}
				else if(_velocity_space.equals("world") && _z_orient && !_alpha_blended)
				{
					default_techniques.add(Pair<Technique*, String>(ContentLibrary::getContent<Technique>("ParticleSystem_birthlocal_velocityworld_zorient"), _process));
				}
				else if(_velocity_space.equals("local") && !_z_orient && !_alpha_blended)
				{
					default_techniques.add(Pair<Technique*, String>(ContentLibrary::getContent<Technique>("ParticleSystem_birthlocal_velocitylocal"), _process));
				}
				else if(_velocity_space.equals("world") && !_z_orient && !_alpha_blended)
				{
					default_techniques.add(Pair<Technique*, String>(ContentLibrary::getContent<Technique>("ParticleSystem_birthlocal_velocityworld"), _process));
				}
				else
				{
					error("This should never happen: contact Mike");
				}
			}*/
			//if(_birth_space.equals("world"))
			//{

			if(_process_handle == -1 )
				error(StringBuilder() << this->getParentGameObject()->name() << " particle system nees a process handle");

			if(_velocity_space.equals("local") && _z_orient && _blending.equals("alpha"))
			{
				default_techniques.add(_process_handle, ContentLibrary::getContent<Technique>("ParticleSystem_velocitylocal_zorient_alphablended"));
			}
			else if(_velocity_space.equals("world") && _z_orient && _blending.equals("alpha"))
			{
				default_techniques.add(_process_handle, ContentLibrary::getContent<Technique>("ParticleSystem_velocityworld_zorient_alphablended"));
			}
			else if(_velocity_space.equals("local") && !_z_orient && _blending.equals("alpha"))
			{
				default_techniques.add(_process_handle, ContentLibrary::getContent<Technique>("ParticleSystem_velocitylocal_alphablended"));
			}
			else if(_velocity_space.equals("world") && !_z_orient && _blending.equals("alpha"))
			{
				default_techniques.add(_process_handle, ContentLibrary::getContent<Technique>("ParticleSystem_velocityworld_alphablended"));
			}
			else if(_velocity_space.equals("local") && _z_orient && _blending.equals("additive"))
			{
				default_techniques.add(_process_handle, ContentLibrary::getContent<Technique>("ParticleSystem_velocitylocal_zorient"));
			}
			else if(_velocity_space.equals("world") && _z_orient && _blending.equals("additive"))
			{
				default_techniques.add(_process_handle, ContentLibrary::getContent<Technique>("ParticleSystem_velocityworld_zorient"));
			}
			else if(_velocity_space.equals("local") && !_z_orient && _blending.equals("additive"))
			{
				default_techniques.add(_process_handle, ContentLibrary::getContent<Technique>("ParticleSystem_velocitylocal"));
			}
			else if(_velocity_space.equals("world") && !_z_orient && _blending.equals("additive"))
			{
				default_techniques.add(_process_handle, ContentLibrary::getContent<Technique>("ParticleSystem_velocityworld"));
			}
			else
			{
				error("This should never happen: contact Mike");
			}

			if(default_techniques.elements() <= 0)
			{
				error(StringBuilder() << "Error: Particle system technique loaded incorrectly: \n" /*<< 
					default_techniques[0].first->getPath()*/ << "\nCheck to make sure the ParticleSystemTechniqes.AssetList is being loaded"); 
			}
			//}

			_mesh_renderer->_techniques = default_techniques;

			_mesh_renderer->_constant_buffer_group = this->_particle_info;

			//generate the key for our meshfilter which will hold the directx buffer.
			StringBuilder mesh_filter_key;
			mesh_filter_key << this->_blending;
			mesh_filter_key << this->_max_particles;
			mesh_filter_key << this->_num_emitters;
			mesh_filter_key << this->_velocity_space;
			mesh_filter_key << this->_z_orient;
			mesh_filter_key << this->_texture->getKey();
			mesh_filter_key << this->_clone_key;

			this->_mesh_filter_key = mesh_filter_key;

			ParticleBufferInfo* pbi = new ParticleBufferInfo();

			pbi->setParticleTexture(this->_texture);

			_mesh_renderer->_process_specific_data = pbi;

			
			_mesh_renderer->_meshes = NULL;


			_mesh_renderer->_name = StringBuilder() << this->_mesh_filter_key;


			//_mesh_renderer_name = _mesh_renderer->getName();

			_mesh_id = _mesh_renderer->_my_id;

			_mesh_renderer->_particle_system = true;

			

			this->getParentGameObject()->addComponent(_mesh_renderer);
			

			if(_clone_key == -1)
			{
				error(StringBuilder() << "Missing clone key on particle System\n" << _mesh_renderer_name << "\n" <<
					*(this->getParentGameObject()));
			}

			return this;
		}

		void ParticleSystem::handle_enabled_message(IMessageReceiver* me, IMessage* msg)
		{
			if(const SetParticleSystemEnabledMessage* spsem = msg->as<SetParticleSystemEnabledMessage>())
			{
				//hout << "Receiverd particle system enabled message";
				ParticleSystem* _this = (ParticleSystem*)me;
				if(spsem->_particle_system_enabled)
				{
					_this->_enabled = 1;
					ParticleBufferInfo* pbi = (ParticleBufferInfo*)_this->_mesh_renderer->_process_specific_data;
					pbi->_first_run = true;
					
				}
				else
				{
					_this->_enabled = 0;
				}

				ConstantBufferModifier* cbm = Factory::acquire<ConstantBufferModifier>();
				cbm->_names.add("gEnabled");
				cbm->_data.add(&_this->_enabled);
				cbm->_types.add(Primitive::HFLOAT);
				cbm->_register = 3;
				Messenger::sendMessage(cbm, _this->_mesh_renderer);
			}
		}

		void ParticleSystem::handle_pulse_message(IMessageReceiver* me, IMessage* msg)
		{
			if(const ParticleSystemPulseMessage* pspm = msg->as<ParticleSystemPulseMessage>())
			{
				//hout << "Receiverd pulse message\n";
				ParticleSystem* _this = (ParticleSystem*)me;

				_this->_pulse_time = pspm->_pulse_length;

				_this->_enabled = 1;
				ConstantBufferModifier* cbm = Factory::acquire<ConstantBufferModifier>();
				cbm->_names.add("gEnabled");
				cbm->_data.add(&_this->_enabled);
				cbm->_types.add(Primitive::HFLOAT);
				cbm->_register = 3;
				Messenger::sendMessage(cbm, _this->_mesh_renderer);
			}
		}

		void ParticleSystem::handle_attributes_message(IMessageReceiver* me, IMessage* msg)
		{
			if(const SetParticleSystemAttributes* spsa = msg->as<SetParticleSystemAttributes>())
			{
				ParticleSystem* _this = (ParticleSystem*)me;

				_this->_rotation = spsa->_rotation;

				ConstantBufferModifier* cbm = Factory::acquire<ConstantBufferModifier>();
				cbm->_names.add("rotation");
				cbm->_data.add(&_this->_rotation);
				cbm->_types.add(Primitive::HVECTOR2);
				cbm->_register = 3;
				Messenger::sendMessage(cbm, _this->_mesh_renderer);

			}
		}

		void ParticleSystem::onSetActive()
		{
			ConstantBufferModifier* cbm = Factory::acquire<ConstantBufferModifier>();
			cbm->_names.add("gEnabled");
			cbm->simpleFloat(1.0f);
			cbm->_types.add(Primitive::HFLOAT);
			cbm->_register = 3;
			
			ParticleBufferInfo* pbi = (ParticleBufferInfo*)this->_mesh_renderer->_process_specific_data;
			pbi->_first_run = true;

			_rot_matrix = this->getParentGameObject()->getTransform().getWorldRotation();
			_cam_up = Vector4(_dx11_director->_active_camera->getUp(),1);
			_cam_right = Vector4(_dx11_director->_active_camera->getRight(),1);
			_cam_forward = Vector4(_dx11_director->_active_camera->getForward(),1);
				

			Messenger::forwardMessage(this->_modifier_message, this->_mesh_renderer);
					
			hout << StringBuilder() <<  "MeshRenderer: " << this->_mesh_renderer << endl;
			this->_mesh_renderer->_constant_buffer_group.handleConstantBufferModifier(cbm);

			Factory::release(cbm);
		}

		void ParticleSystem::onSetInactive()
		{
			ConstantBufferModifier* cbm = Factory::acquire<ConstantBufferModifier>();
			cbm->_names.add("gEnabled");
			cbm->simpleFloat(0.0f);
			cbm->_types.add(Primitive::HFLOAT);
			cbm->_register = 3;
			
			this->_mesh_renderer->_constant_buffer_group.handleConstantBufferModifier(cbm);

			Factory::release(cbm);
		}
	}
}